use std::{
    collections::HashMap,
    fmt::{Debug, Display},
    mem::MaybeUninit,
};

use common_base::{
    bigdecimal::BigDecimal,
    prelude::*,
    sqlx::{mysql::MySqlRow, Column, Row},
    uuid::Uuid,
};

use crate::util::MapUtil;

use super::{
    data_status::DataStatus, data_value::DataValue, DatasetOwner, DatasetRef, DatasetType,
    RowsetOwner, RowsetRef,
};

/// for safety reason, RowsetRef/RowsetOwner/DatasetRef/DatasetOwner must not `pub(crate)`
///
// #[derive(Debug, serde::Serialize, serde::Deserialize)]
// #[serde(crate = "self::serde")]
// #[serde(rename_all = "camelCase")]
#[derive(Debug, Clone)]
pub struct Rowset {
    pub(crate) uuid: String,
    pub(crate) data_status: DataStatus,
    pub(super) master_table_name: Option<String>,
    pub(super) master: Option<RowsetRef>,
    pub(super) owner_dataset: Option<DatasetRef>,
    pub(super) self_ref: MaybeUninit<RowsetRef>, // TODO: maybe a Week Ref instead
    //
    pub(crate) data_map: HashMap<String, RowField>,
    pub(crate) dataset_map: HashMap<String, DatasetOwner>,
    pub(crate) ext_rowset_map: HashMap<String, RowsetOwner>,
    //
    pub(crate) front_id_2_name_map: HashMap<String, RowField>,
    pub(crate) back_id_2_name_map: HashMap<String, RowField>,
    //
    pub(super) dataset_map_list: Vec<DatasetRef>,
    pub(super) dataset_view_list: Vec<DatasetRef>,
    pub(super) dataset_cont_list: Vec<DatasetRef>,
    // extPropertys
    // dataMapBak
}

// we must guarantee that: `master` and other NonNull field must NOT used between threads!!!
unsafe impl Send for Rowset {}

impl Default for Rowset {
    fn default() -> Self {
        Self {
            uuid: Uuid::new_v4().to_string(),
            data_status: DataStatus::Normal,
            master_table_name: Default::default(),
            master: Default::default(),
            owner_dataset: None,
            self_ref: MaybeUninit::uninit(),
            data_map: Default::default(),
            dataset_map: Default::default(),
            ext_rowset_map: Default::default(),
            front_id_2_name_map: Default::default(),
            back_id_2_name_map: Default::default(),
            dataset_map_list: Vec::default(),
            dataset_view_list: Vec::default(),
            dataset_cont_list: Vec::default(),
        }
    }
}

impl TryFrom<MySqlRow> for Rowset {
    type Error = ErrorCode;

    fn try_from(db_row: MySqlRow) -> std::result::Result<Self, Self::Error> {
        let mut rowset = Rowset::default();
        for col in db_row.columns() {
            let value = db_row.try_get_raw(col.ordinal())?;

            let data_value: DataValue = (col.ordinal(), value).try_into()?;
            rowset.put_object(col.name(), data_value.into());
        }
        rowset.data_status = DataStatus::Normal;
        Ok(rowset)
    }
}

impl Display for Rowset {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.get_string("caption"))
    }
}

/// serizlize and deserizlize
impl Rowset {
    pub fn deserizlize_from_json(mut rowset_json: serde_json::Value) -> Result<Self> {
        let data_status =
            if let Some(data_status) = rowset_json.get_mut("dataStatus").and_then(|v| v.as_i64()) {
                DataStatus::try_from(data_status as i32)?
            } else {
                return Err(ErrorCode::RequestInvalid(
                    "can not deserizlize dataStatus from Rowset",
                ));
            };

        let data_map = if let Some(data_map_json) = rowset_json
            .get_mut("dataMap")
            .and_then(|v| v.as_object_mut())
        {
            let mut data_map = HashMap::with_capacity(data_map_json.len());
            for (row_key, row_field) in data_map_json.iter_mut() {
                data_map.insert(
                    row_key.clone(),
                    RowField::deserizlize_from_json(row_field.take())?,
                );
            }
            data_map
        } else {
            return Err(ErrorCode::RequestInvalid(
                "can not deserizlize dataMap from Rowset",
            ));
        };

        let dataset_map = if let Some(dataset_map_json) = rowset_json
            .get_mut("dataSetMap")
            .and_then(|v| v.as_object_mut())
        {
            let mut dataset_map = HashMap::with_capacity(dataset_map_json.len());
            for (dataset_key, dataset) in dataset_map_json.iter_mut() {
                dataset_map.insert(
                    dataset_key.clone(),
                    DatasetOwner::deserizlize_from_json(dataset.take())?,
                );
            }
            dataset_map
        } else {
            return Err(ErrorCode::RequestInvalid(
                "can not deserizlize dataSetMap from Rowset",
            ));
        };

        let back_id_2_name_map = if let Some(back_id_2_name_map_json) = rowset_json
            .get_mut("backID2NameMap")
            .and_then(|v| v.as_object_mut())
        {
            let mut back_id_2_name_map = HashMap::with_capacity(back_id_2_name_map_json.len());
            for (row_key, row_field) in back_id_2_name_map_json.iter_mut() {
                back_id_2_name_map.insert(
                    row_key.clone(),
                    RowField::deserizlize_from_json(row_field.take())?,
                );
            }
            back_id_2_name_map
        } else {
            return Err(ErrorCode::RequestInvalid(
                "can not deserizlize backID2NameMap from Rowset",
            ));
        };

        Ok(Self {
            uuid: Uuid::new_v4().to_string(),
            data_status,
            master_table_name: None,
            master: None,
            owner_dataset: None,
            self_ref: MaybeUninit::uninit(),
            data_map,
            dataset_map,
            ext_rowset_map: Default::default(),
            front_id_2_name_map: Default::default(),
            back_id_2_name_map,
            dataset_map_list: Default::default(),
            dataset_view_list: Default::default(),
            dataset_cont_list: Default::default(),
        })
    }
}

/// common attribute
impl Rowset {
    pub fn uuid(&self) -> &str {
        &self.uuid
    }

    pub fn set_master_table_name(&mut self, table_name: &str) {
        if self.master_table_name.is_none() {
            self.master_table_name = Some(table_name.to_owned())
        }
    }

    pub fn set_master(&mut self, master: RowsetRef) {
        if self.master.is_none() {
            self.master = Some(master)
        }
    }

    pub fn set_owner_dataset(&mut self, dataset: DatasetRef) {
        self.owner_dataset = Some(dataset);
    }

    fn self_ref(&self) -> RowsetRef {
        unsafe { self.self_ref.assume_init_read() }
    }

    pub fn set_self_ref(&mut self, self_ref: RowsetRef) {
        self.self_ref.write(self_ref);
    }
}

/// operate on `data_map`
const DEPEND_DCT_ITEM: &'static str = "_dependDCT_ITEM_";
impl Rowset {
    pub fn get_string(&self, key: &str) -> &str {
        self.get_string_default(key, "")
    }

    pub fn get_string_default<'a>(&'a self, key: &str, default_value: &'a str) -> &'a str {
        MapUtil::get_string_with_depend(
            &self.data_map,
            key,
            default_value,
            self.get_ext_rowset(DEPEND_DCT_ITEM),
        )
    }

    pub fn get_int(&self, key: &str, default: i32) -> i32 {
        match self.get_object(key) {
            Some(RowField::Value(DataValue::String(inner))) => {
                inner.parse::<i32>().unwrap_or(default)
            }
            Some(RowField::Value(DataValue::BigDecimal(inner))) => inner.digits() as i32,
            Some(_) | None => default,
        }
    }

    pub fn contains_key(&self, key: &str) -> bool {
        self.data_map.contains_key(key)
    }

    pub fn get_object(&self, key: &str) -> Option<&RowField> {
        MapUtil::get_object(&self.data_map, key)
    }

    pub fn get_object_mut(&mut self, key: &str) -> Option<&mut RowField> {
        MapUtil::get_object_mut(&mut self.data_map, key)
    }

    // pub fn put_string(&mut self, key: &str, value: &str) {
    //     self.put_object(key, DataValue::String(value.to_owned()).into())
    // }

    pub fn put_string(&mut self, key: &str, value: String) {
        self.put_object(key, DataValue::String(value).into())
    }

    pub fn put_object(&mut self, key: &str, object: RowField) {
        self.data_map.insert(key.to_owned(), object);
        // TODO
    }

    // pub fn put_dataset
}

/// operate on `dataset_map`
impl Rowset {
    pub fn insert_dataset(&mut self, key: &str, mut dataset: DatasetOwner) {
        dataset.set_master(self.self_ref());
        dataset.set_parent_rowset(self.self_ref());
        dataset.insert_child_rowset(self.self_ref());

        self.put_dataset(key, dataset);
    }

    pub fn put_dataset(&mut self, key: &str, dataset: DatasetOwner) {
        self.dataset_map.insert(key.to_owned(), dataset);
    }

    pub fn get_dataset(&self, dataset_key: &str) -> Option<&DatasetOwner> {
        self.dataset_map.get(dataset_key)
    }

    pub fn get_dataset_mut(&mut self, dataset_key: &str) -> Option<&mut DatasetOwner> {
        self.dataset_map.get_mut(dataset_key)
    }
}

/// operate on `ext_rowset_map`
impl Rowset {
    pub fn get_ext_rowset(&self, key: &str) -> Option<&RowsetOwner> {
        self.ext_rowset_map.get(key)
    }
}

/// operate on `dataset_map_list`/`dataset_view_list`/`dataset_cont_list`
impl Rowset {
    pub fn insert_dataset_manager(&mut self, dataset: DatasetRef) {
        match dataset.to_owner_ref().dataset_type() {
            DatasetType::Map => self.insert_dataset_map(dataset),
            DatasetType::View => self.insert_dataset_view(dataset),
            DatasetType::Container => self.insert_dataset_cont(dataset),
        }
    }

    fn insert_dataset_map(&mut self, dataset: DatasetRef) {
        self.dataset_map_list.push(dataset);
    }

    fn insert_dataset_view(&mut self, dataset: DatasetRef) {
        self.dataset_view_list.push(dataset);
    }

    fn insert_dataset_cont(&mut self, dataset: DatasetRef) {
        self.dataset_cont_list.push(dataset);
    }
}

// #[derive(Debug, serde::Serialize, serde::Deserialize)]
#[derive(Debug)]
// #[serde(untagged)]
pub enum RowField {
    Value(DataValue),
    Rowset(RowsetOwner),
    List(Vec<RowField>),
    Map(HashMap<String, RowField>),
    Object(Box<dyn AsRowField>),
}

impl From<String> for RowField {
    fn from(v: String) -> Self {
        RowField::Value(DataValue::String(v))
    }
}

impl From<&str> for RowField {
    fn from(v: &str) -> Self {
        RowField::Value(DataValue::String(v.to_owned()))
    }
}

impl From<bool> for RowField {
    fn from(v: bool) -> Self {
        RowField::Value(DataValue::Bool(v))
    }
}

impl From<serde_json::Number> for RowField {
    fn from(v: serde_json::Number) -> Self {
        if let Some(v) = v.as_i64() {
            RowField::Value(DataValue::I64(v))
        } else if let Some(v) = v.as_u64() {
            RowField::Value(DataValue::U64(v))
        } else if let Some(v) = v.as_f64() {
            RowField::Value(DataValue::F64(v))
        } else {
            unreachable!()
        }
    }
}

impl From<DataValue> for RowField {
    fn from(v: DataValue) -> Self {
        RowField::Value(v)
    }
}

impl From<RowsetOwner> for RowField {
    fn from(v: RowsetOwner) -> Self {
        RowField::Rowset(v)
    }
}

impl From<Vec<RowField>> for RowField {
    fn from(v: Vec<RowField>) -> Self {
        RowField::List(v)
    }
}

impl From<HashMap<String, RowField>> for RowField {
    fn from(v: HashMap<String, RowField>) -> Self {
        RowField::Map(v)
    }
}

impl From<Box<dyn AsRowField>> for RowField {
    fn from(v: Box<dyn AsRowField>) -> Self {
        RowField::Object(v)
    }
}

impl Clone for RowField {
    fn clone(&self) -> Self {
        match self {
            Self::Value(inner) => Self::Value(inner.clone()),
            Self::Rowset(inner) => Self::Rowset(inner.clone()),
            Self::List(inner) => Self::List(inner.clone()),
            Self::Map(inner) => Self::Map(inner.clone()),
            Self::Object(inner) => Self::Object(inner.object_clone()),
        }
    }
}

impl Display for RowField {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            RowField::Value(inner) => Display::fmt(&inner, f),
            RowField::Rowset(inner) => Display::fmt(&inner, f),
            RowField::List(inner) => todo!(),
            RowField::Map(inner) => todo!(),
            RowField::Object(inner) => todo!(),
        }
    }
}

impl PartialEq for RowField {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Self::Value(l0), Self::Value(r0)) => l0 == r0,
            (Self::Rowset(l0), Self::Rowset(r0)) => todo!(),
            (Self::List(l0), Self::List(r0)) => todo!(),
            (Self::Map(l0), Self::Map(r0)) => todo!(),
            (Self::Object(l0), Self::Object(r0)) => todo!(),
            _ => todo!(),
        }
    }
}
impl Eq for RowField {}

impl PartialOrd for RowField {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        match (self, other) {
            (Self::Value(l0), Self::Value(r0)) => l0.partial_cmp(r0),
            (Self::Rowset(l0), Self::Rowset(r0)) => todo!(),
            (Self::List(l0), Self::List(r0)) => todo!(),
            (Self::Map(l0), Self::Map(r0)) => todo!(),
            (Self::Object(l0), Self::Object(r0)) => todo!(),
            _ => todo!(),
        }
    }
}
impl Ord for RowField {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.partial_cmp(other).unwrap_or(std::cmp::Ordering::Equal)
    }
}

impl RowField {
    pub fn deserizlize_from_json(row_field_json: serde_json::Value) -> Result<Self> {
        match row_field_json {
            serde_json::Value::Object(_) => {
                Ok(RowsetOwner::deserizlize_from_json(row_field_json)?.into())
            }
            serde_json::Value::Array(list) => {
                let mut rowset_list = Vec::with_capacity(list.len());
                for rowset_json in list {
                    rowset_list.push(RowField::deserizlize_from_json(rowset_json)?);
                }
                Ok(rowset_list.into())
            }
            serde_json::Value::Null => Ok(RowField::Value(DataValue::Null)),
            serde_json::Value::Bool(v) => Ok(v.into()),
            serde_json::Value::Number(v) => Ok(v.into()),
            serde_json::Value::String(v) => Ok(v.into()),
        }
    }
}

impl RowField {
    pub fn as_value(&self) -> Option<&DataValue> {
        if let RowField::Value(inner) = self {
            Some(inner)
        } else {
            None
        }
    }
    pub fn as_map(&self) -> Option<&HashMap<String, RowField>> {
        if let RowField::Map(inner) = self {
            Some(inner)
        } else {
            None
        }
    }
    pub fn as_map_mut(&mut self) -> Option<&mut HashMap<String, RowField>> {
        if let RowField::Map(inner) = self {
            Some(inner)
        } else {
            None
        }
    }
    pub fn as_object(&self) -> Option<&Box<dyn AsRowField>> {
        if let RowField::Object(inner) = self {
            Some(inner)
        } else {
            None
        }
    }
}

pub trait AsRowField: std::fmt::Debug {
    fn as_any(&self) -> &dyn std::any::Any;

    fn object_clone(&self) -> Box<dyn AsRowField>;
}
